﻿#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <complex>
#include <cmath>
#include <algorithm>
//#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/nonfree/nonfree.hpp>


/****************************************************************************/
using namespace std;
using namespace cv;
/****************************************************************************/
int main() 
{
	
	Mat img1 = imread("spiderman1.jpg", CV_LOAD_IMAGE_GRAYSCALE);
	Mat img2 = imread("spiderman4.jpg", CV_LOAD_IMAGE_GRAYSCALE);
	if(img1.empty() || img2.empty())
	{
		return -1;
	}
	//////////////////////////////////////////////////////////////////////////
	//Display images
	imshow("Left  Image", img1);
	imshow("Right Image", img2);

	//////////////////////////////////////////////////////////////////////////
	//Vector of Key points
	vector<KeyPoint> keypoints1;
	vector<KeyPoint> keypoints2;
	
	//////////////////////////////////////////////////////////////////////////
	//Construct SURF Feature Detector
	Ptr<FeatureDetector> surfDetector = new SURF(600.0);

	surfDetector->detect(img1,keypoints1);
	surfDetector->detect(img2,keypoints2);

	cout << "Number of SURF points (1): " << keypoints1.size() << endl;
	cout << "Number of SURF points (2): " << keypoints2.size() << endl;
	//////////////////////////////////////////////////////////////////////////
	// Draw the key points
	Mat imageKP;
	drawKeypoints(img1, keypoints1, 
		          imageKP, Scalar(255,255,255), 
				  DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
	imshow("Left  Fast Features", imageKP);
	drawKeypoints(img2, keypoints2, 
		          imageKP, Scalar(255,255,255), 
				  DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
	imshow("Right Fast Features", imageKP);

	//////////////////////////////////////////////////////////////////////////
 	Mat descriptors1, descriptors2;
 	Ptr<DescriptorExtractor> surfExtractor = new SURF(600.0);
	surfExtractor->compute(img1, keypoints1, descriptors1);
	surfExtractor->compute(img2, keypoints2, descriptors2);

	cout << "Descriptor matrix size: " << descriptors1.rows 
		 << " by " << descriptors1.cols << endl;
	//////////////////////////////////////////////////////////////////////////
	// Construction of the matcher 
//  	Ptr<DescriptorMatcher> descriptorMatcher = new DescriptorMatcher()
//  	vector<DMatch> matches;
//  
//  	descriptorMatcher->match(descriptors1, descriptors2, matches);
//  	cout << "Number of matched points: " << matches.size() << endl;
	FlannBasedMatcher matcher;
	vector<DMatch> matches;
	matcher.match(descriptors1, descriptors2, matches);
	cout << "Number of matched points: " << matches.size() << endl;
	//////////////////////////////////////////////////////////////////////////
	double max_dist = 0; double min_dist = 100;

	//Quick calculation of max and min distances between keypoints
	for( int i = 0; i < descriptors1.rows; i++ )
	{ 
		double dist = matches[i].distance;
		if(dist<min_dist) 
			min_dist = dist;
		if(dist>max_dist) 
			max_dist = dist;
	}

	cout << "-- Max dist : "<< max_dist <<endl;
	cout << "-- Min dist : "<< min_dist <<endl;

	//Draw only "good" matches (i.e. whose distance is less than 3*min_dist )
	std::vector< DMatch > good_matches;

	for(int i=0; i<descriptors1.rows; i++)
	{ 
		if(matches[i].distance < 3*min_dist)
			good_matches.push_back( matches[i]); 
	}

	Mat img_matches;
	drawMatches(img1, keypoints1, 
			    img2, keypoints2, 
				good_matches, img_matches, 
				Scalar::all(-1), Scalar::all(-1),
	vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
	imshow("Matches Point", img_matches);
	//////////////////////////////////////////////////////////////////////////
	waitKey();
	return 0;
}
/****************************************************************************/